/*
 * $Id: NavigationView.java 135 2009-07-15 09:04:20Z donbeave $
 */

package labour.manager.client.mvc;

import java.util.List;

import labour.concept.client.data.Locale;
import labour.concept.client.data.ObjectText;
import labour.concept.client.data.ObjectType;
import labour.concept.engine.client.data.EngineManager;
import labour.concept.engine.client.data.EngineObject;
import labour.concept.engine.client.data.Site;
import labour.manager.client.AppEvents;
import labour.manager.client.NavigationEvents;
import labour.manager.client.data.InfoStructureStore;
import labour.manager.client.widget.form.LocaleForm;
import labour.manager.client.widget.form.ObjectForm;
import labour.manager.client.widget.form.ObjectTextForm;
import labour.manager.client.widget.form.SiteForm;
import labour.manager.client.widget.form.WebObjectForm;
import labour.manager.client.widget.menu.CreateDocumentMenu;
import labour.manager.client.widget.menu.NavigationContextMenu;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.Style.Scroll;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.ModelStringProvider;
import com.extjs.gxt.ui.client.event.EventType;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MenuEvent;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.event.WindowEvent;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.extjs.gxt.ui.client.mvc.View;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Dialog;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.TabPanel;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.extjs.gxt.ui.client.widget.menu.SeparatorMenuItem;
import com.extjs.gxt.ui.client.widget.treepanel.TreePanel;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class NavigationView extends View {

  public static final String INFO_TREE = "NavigationView.INFO_TREE";

  private TreePanel<ModelData> treePanel;

  private NavigationContextMenu infoContextMenu;

  public NavigationView(Controller controller) {
    super(controller);
  }

  protected void handleEvent(AppEvent event) {
    EventType type = event.getType();

    if (type == AppEvents.Ready) {
      onPrepare();
    }
    else if (type == NavigationEvents.ShowProperties) {
      if (event.getData() instanceof Site) {
        onViewSiteProperties((Site) event.getData());
      }
      else if (event.getData() instanceof Locale) {
        onViewLocaleProperties((Locale) event.getData());
      }
      else if (event.getData() instanceof ObjectText) {
        onViewObjectProperties((ObjectText) event.getData());
      }
    }
  }

  protected void initialize() {
    InfoStructureStore store = Registry.get(NavigationController.INFO_STORE);

    treePanel = new TreePanel<ModelData>(store);
    treePanel.setStateful(true);
    treePanel.setDisplayProperty("Name");

    treePanel.setLabelProvider(new ModelStringProvider<ModelData>() {
      public String getStringValue(ModelData model, String property) {
        if (model instanceof Locale) {
          String lang = ((Locale) model).getModel().getLanguage();

          if (lang.equals(Locale.RU)) {
            return "Russian version";
          }
          else if (lang.equals(Locale.EN)) {
            return "English version";
          }
          return ((Locale) model).getLanguage();
        }
        return model.get(property);
      }
    });

    Registry.register(INFO_TREE, treePanel);
  }

  protected void onPrepare() {
    ContentPanel eastPanel = Registry.get(AppView.EAST_PANEL);

    ContentPanel panel = new ContentPanel();
    panel.setHeading("Info Structure Navigation");
    panel.setLayout(new FitLayout());
    panel.setSize(315, 400);

    initNavigationContextMenu();

    panel.add(treePanel);

    eastPanel.add(panel);
  }

  protected void initNavigationContextMenu() {
    // creating menu
    infoContextMenu = new NavigationContextMenu(treePanel);

//    initCreateMenu();

    // adding menu to tree
    treePanel.setContextMenu(infoContextMenu);

    Listener<MenuEvent> propertiesListener = new Listener<MenuEvent>() {
      public void handleEvent(MenuEvent menuEvent) {
        AppEvent event = new AppEvent(NavigationEvents.ShowProperties, treePanel.getSelectionModel().getSelectedItem());

        Dispatcher.forwardEvent(event);
      }
    };

    // adding properties listener to site context menu
    infoContextMenu.getSiteMenu().getPropertiesItem().addListener(Events.Select, propertiesListener);

    // adding properties listener to locale context menu
    infoContextMenu.getLocaleMenu().getPropertiesItem().addListener(Events.Select, propertiesListener);

    // adding properties listener to object context menu
    infoContextMenu.getObjectMenu().getPropertiesItem().addListener(Events.Select, propertiesListener);


    Listener<MenuEvent> prepareCreateMenuListener = new Listener<MenuEvent>() {
      public void handleEvent(MenuEvent menuEvent) {
        prepareCreateMenu((CreateDocumentMenu) menuEvent.getContainer());
      }
    };

    infoContextMenu.getLocaleMenu().getCreateItem().getSubMenu().addListener(Events.BeforeShow, prepareCreateMenuListener);

    infoContextMenu.getObjectMenu().getCreateItem().getSubMenu().addListener(Events.BeforeShow, prepareCreateMenuListener);


    Listener<MenuEvent> refreshListener = new Listener<MenuEvent>() {
      public void handleEvent(MenuEvent menuEvent) {
        AppEvent event = new AppEvent(NavigationEvents.Refresh, treePanel.getSelectionModel().getSelectedItem());

        Dispatcher.forwardEvent(event);
      }
    };

    infoContextMenu.getSiteMenu().getRefreshItem().addListener(Events.Select, refreshListener);

    infoContextMenu.getLocaleMenu().getRefreshItem().addListener(Events.Select, refreshListener);

    infoContextMenu.getObjectMenu().getRefreshItem().addListener(Events.Select, refreshListener);


    infoContextMenu.getObjectMenu().getDeleteItem().addListener(Events.Select, new Listener<MenuEvent>() {
      public void handleEvent(MenuEvent be) {
        MessageBox.confirm("Delete object", "Are you sure you want delete this object?", new Listener<MessageBoxEvent>() {
          public void handleEvent(MessageBoxEvent be) {
            if (be.getButtonClicked().getItemId().equals(Dialog.YES)) {
              AppEvent event = new AppEvent(NavigationEvents.DeleteObject, treePanel.getSelectionModel().getSelectedItem());

              Dispatcher.forwardEvent(event);
            }
          }
        });
      }
    });

    infoContextMenu.getLocaleMenu().getUseByDefaultItem().addListener(Events.Select, new Listener<MenuEvent>() {
      public void handleEvent(MenuEvent be) {
        EngineManager manager = Registry.get(AppController.MANAGER);

        manager.setDefaultLocale((Locale) treePanel.getSelectionModel().getSelectedItem());
      }
    });
  }

  protected void prepareCreateMenu(CreateDocumentMenu menu) {
    menu.removeAllListeners();
    menu.removeAdditionalItems();

    // adding new item to menu
    EngineManager manager = Registry.get(AppController.MANAGER);

    List<ObjectType> typesList = manager.getObjectsTypes();

    if (!typesList.isEmpty()) {
      // first adding separator
      menu.add(new SeparatorMenuItem());

      // adding items
      for (ObjectType type : typesList) {
        if (type.getModel().getName().equals("container")) {
          menu.getFolderItem().setData("object", type);
        } else {
          MenuItem item = new MenuItem(type.getModel().getName());
          item.setData("object", type);

          menu.add(item);
        }
      }
    }

    Listener<MenuEvent> createListener = new Listener<MenuEvent>() {
      public void handleEvent(final MenuEvent menuEvent) {
        MessageBox.prompt("Create new object", "Name", new Listener<MessageBoxEvent>() {
          public void handleEvent(MessageBoxEvent be) {
            if (be.getButtonClicked().getItemId().equals(MessageBox.OK)) {
              AppEvent event = new AppEvent(NavigationEvents.CreateObject);
              event.setData(menuEvent.getItem().getData("object"));
              event.setData("Name", be.getValue());

              ModelData selectedItem = treePanel.getSelectionModel().getSelectedItem();

              if (selectedItem instanceof Locale) {
                event.setData("Locale", selectedItem);
              }
              else if (selectedItem instanceof ObjectText) {
                event.setData("Locale", ((ObjectText) selectedItem).getLocale());
                event.setData("Parent", ((ObjectText) selectedItem).getObject());
              }

              Dispatcher.forwardEvent(event);
            }
          }
        });
      }
    };

    for (int i = 0; i < menu.getItemCount(); i++) {
      if (menu.getItem(i) instanceof MenuItem) {
        MenuItem item = (MenuItem) menu.getItem(i);

        if (!item.getText().equals(menu.getShortcutItem().getText())) {
          item.addListener(Events.Select, createListener);
        }
      }
    }
  }

  protected void onViewSiteProperties(Site site) {
    Dialog dialog = createPropertiesDialog("Site Properties");
    dialog.setScrollMode(Scroll.AUTO);

    dialog.setMinHeight(200);
    dialog.setHeight(200);

    SiteForm form = new SiteForm(site);
    form.setHeaderVisible(false);
    form.setBorders(false);

    dialog.add(form);

    dialog.show();
  }

  protected void onViewLocaleProperties(Locale locale) {
    Dialog dialog = createPropertiesDialog("Locale Properties");

    LocaleForm form = new LocaleForm(locale);
    form.setHeaderVisible(false);
    form.setBorders(false);


    dialog.add(form);

    dialog.show();
  }

  protected void onViewObjectProperties(final ObjectText item) {
    Dialog dialog = createPropertiesDialog("Object Properties (" + item.getName() + ")");

    final TabPanel tabPanel = new TabPanel();
    tabPanel.setBorders(false);

    // creating general tab
    TabItem generalTab = new TabItem("Object");
    generalTab.setItemId("GeneralTab");
    generalTab.setLayout(new FitLayout());

    // creating web tab
    TabItem webTab = new TabItem("Web");
    webTab.setItemId("WebTab");
    webTab.setLayout(new FitLayout());

    // creating object's localized data tab
    TabItem localizedTab = new TabItem("Localized data");
    localizedTab.setItemId("LocalizedTab");
    localizedTab.setLayout(new FitLayout());

    // creating general object form
    final ObjectForm form = new ObjectForm(item.getObject());
    form.setItemId("ObjectForm");
    form.setHeaderVisible(false);
    form.setBorders(false);
    form.getTypesBox().disable();

    // adding forms to tabs
    generalTab.add(form); // general object form to general tab


    final WebObjectForm webForm;

    if (item.getObject() instanceof EngineObject) {
      // creating web object form
      webForm = new WebObjectForm((EngineObject) item.getObject());
      webForm.setItemId("WebObjectForm");
      webForm.setHeaderVisible(false);
      webForm.setBorders(false);

      webTab.add(webForm);
    }

    // creating localized data's form
    final ObjectTextForm textForm = new ObjectTextForm(item);
    textForm.setItemId("TextForm");
    textForm.setHeaderVisible(false);
    textForm.setBorders(false);
    textForm.getLocalesBox().disable();


    Button edit = new Button("Edit another localized version");

    Menu menu = new Menu();

    List<Locale> locales = ((EngineObject) item.getObject()).getSite().getLocales();

    for (final Locale locale : locales) {
      MenuItem menuItem = new MenuItem(locale.getLanguage());
      menu.add(menuItem);

      menuItem.addListener(Events.Select, new Listener<MenuEvent>() {
        public void handleEvent(MenuEvent be) {
          if (item.getObject().hasData(locale)) {
            textForm.setModel(item.getObject().getData(locale));
          } else {
            item.getObject().extendData(locale, "<Localized name>");

            textForm.setModel(item.getObject().getData(locale));
          }
        }
      });
    }

    edit.setMenu(menu);

    textForm.add(edit);

    localizedTab.add(textForm);


    // adding tabs to panel
    tabPanel.add(generalTab);
    tabPanel.add(webTab);
    tabPanel.add(localizedTab);

    dialog.add(tabPanel);

    // showing object's properties window
    dialog.show();

    dialog.addListener(Events.Hide, new Listener<WindowEvent>() {
      public void handleEvent(WindowEvent event) {
        if (event.getButtonClicked().getItemId().equals(Dialog.OK)) {
          item.getObject().extendData(textForm.getLocalesBox().getValue(), textForm.getNameField().getValue());

          item.getObject().save(new AsyncCallback<EngineObject>() {
            public void onFailure(Throwable caught) {
              // TODO сделать единый метод для перехвата ошибок
              // onError(caught);
            }

            public void onSuccess(EngineObject result) {
              final AppEvent event = new AppEvent(NavigationEvents.Refresh);
              event.setData(item);

              Dispatcher.forwardEvent(event);
            }
          });
        }
      }
    });
  }

  private Dialog createPropertiesDialog(String heading) {
    Dialog dialog = new Dialog();
    dialog.setHeading(heading);
    dialog.setMinWidth(400);
    dialog.setMinHeight(300);
    dialog.setWidth(400);
    dialog.setHeight(300);

    dialog.setLayout(new FitLayout());

    dialog.setButtons(Dialog.OKCANCEL);
    dialog.setHideOnButtonClick(true);

    return dialog;
  }

}
